package com.heu.blood.storge.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heu.blood.application.entity.BloodApplicationEntity;
import com.heu.blood.common.commponent.DictBloodProductLoader;
import com.heu.blood.common.enums.BloodInformationEnum;
import com.heu.blood.common.enums.BloodStateEnum;
import com.heu.blood.dict.entity.DictBloodProductEntity;
import com.heu.blood.dict.entity.DictDepartmentEntity;
import com.heu.blood.dict.service.DictBloodProductService;
import com.heu.blood.dict.vo.DepartmentDictVo;
import com.heu.blood.globalExceptionHandler.MyException;
import com.heu.blood.match.entity.BloodInformationEntity;
import com.heu.blood.match.service.BloodInformationService;
import com.heu.blood.security.exception.SecurityExceptionEnum;
import com.heu.blood.storge.dictenum.BloodWarningEnum;
import com.heu.blood.storge.entity.BloodInStorgeEntity;
import com.heu.blood.storge.service.BloodInStorgeService;
import com.heu.blood.storge.vo.BloodTypeWarningVo;
import com.heu.blood.storge.vo.BloodWarningQueryVo;
import com.heu.blood.storge.vo.BloodWarningVo;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;

import com.heu.blood.storge.dao.BloodWarningDao;
import com.heu.blood.storge.entity.BloodWarningEntity;
import com.heu.blood.storge.service.BloodWarningService;


@Service("bloodWarningService")
public class BloodWarningServiceImpl extends ServiceImpl<BloodWarningDao, BloodWarningEntity> implements BloodWarningService {

    @Autowired
    private DictBloodProductLoader dictBloodProductLoader;

    @Autowired
    private BloodInformationService bloodInformationService;

    @Autowired
    private DictBloodProductService dictBloodProductService;

    @Autowired
    private BloodInStorgeService bloodInStorgeService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<BloodWarningEntity> page = this.page(
                new Query<BloodWarningEntity>().getPage(params),
                new QueryWrapper<BloodWarningEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<BloodWarningVo> bloodWarningByTime(Map<String, Object> params) {
//        预加载的血液品字典
        Map<String, String> dictCodeMap = dictBloodProductLoader.getchildToParent();
//        血液信息
        List<BloodInformationEntity> list = bloodInformationService.list();
//      映射父节点和它的过期时间
        Map<String, String> timeCodeMap = new HashMap<>();
        List<BloodWarningEntity> bloodWarningEntityList = this.list();
        for (BloodWarningEntity entity: bloodWarningEntityList) {
            timeCodeMap.put(entity.getBloodType(), entity.getTimeWarningValue());
        }
//      映射bloodType及其对应的duration(保质期)
        Map<String, String> codeDurationMap = new HashMap<>();
        List<DictBloodProductEntity> bloodProductEntityList = dictBloodProductService.list();
        for (DictBloodProductEntity entity: bloodProductEntityList) {
            codeDurationMap.put(entity.getDictCode(), entity.getDuration());
        }
//      映射bloodId及其对应的入库时间
        Map<String, Date> IdStorageTimeMap = new HashMap<>();
        List<BloodInStorgeEntity> bloodInStorgeEntities = bloodInStorgeService.list();
        for (BloodInStorgeEntity entity: bloodInStorgeEntities) {
            IdStorageTimeMap.put(entity.getBloodId(), entity.getInStorgeTime());
        }
        List<BloodWarningVo> res = new ArrayList<>();


        Date currentDate = new Date();
        for (BloodInformationEntity entity: list) {
//            bloodInformation是血液在库的状态&&能查到bloodInformation的BloodType对应的父亲结点&&notDelete
            if (entity.getBloodState().equals(BloodStateEnum.IN_STOCK.code()) &&
                    dictCodeMap.get(entity.getBloodType()) != null &&
                    entity.getIsDeleted() == 0) {
                BloodWarningVo bloodWarningVo = new BloodWarningVo();
//                计算时间差
//                没有failureTime 先验知识根据入库时间算
                Date failureTime;
                if (entity.getFailureTime() != null) {
                    failureTime = entity.getFailureTime();
                } else { // 如果没有failureTime查询入库时间
//                    获取bloodInformation的bloodType后，使用map映射到duration
                    String Duration = codeDurationMap.get(entity.getBloodType());
                    Date StorageDate = IdStorageTimeMap.get(entity.getBloodId());
                    // 假设durationString表示天数，将其转换为int
                    int durationDays = Integer.parseInt(Duration);
                    if (Duration != null && StorageDate != null) {
                        // 使用Calendar类计算failureTime
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(StorageDate);
                        calendar.add(Calendar.DAY_OF_YEAR, durationDays);

                        failureTime = calendar.getTime();
                    } else {
                        failureTime = null;
                    }
                    System.out.println(failureTime);
                }
                String timeWarningStr = null;
                long diffInDays = 0;
                if (failureTime != null) {
                    long diffInMillies = failureTime.getTime() - currentDate.getTime();
                    diffInDays = TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
//               diffInDays >= 0 还未过期 要预警 diffInDays < 0 已经过期
//                timeCodeMap.get(dictCodeMap.get(entity.getBloodType()))是血液预警时间 我们要比较 如果 diffIndays小于这个时间了，报警
                    BeanUtils.copyProperties(entity, bloodWarningVo);
//                获取父结点的timeWarning
                    timeWarningStr = timeCodeMap.get(dictCodeMap.get(entity.getBloodType()));
                }
//                  如果有timeWarning 我们才进行过期时间的计算
                if (timeWarningStr != null) {
                    if (diffInDays >= 0 && diffInDays <= Integer.parseInt(timeWarningStr)) {
                        bloodWarningVo.setDaysUntilExpiration((int)diffInDays);
                        res.add(bloodWarningVo);
                    } else if (diffInDays < 0) {
                        bloodWarningVo.setTimeoutDays((int) Math.abs(diffInDays));
                        res.add(bloodWarningVo);
                    }
                }
            }
        }
        return res;
    }

    @Override
    public PageUtils queryByBloodType(BloodWarningQueryVo bloodWarningQueryVo) {
        Map<String,Object> params = new HashMap<>();
        params.put("limit",bloodWarningQueryVo.getLimit());
        params.put("page",bloodWarningQueryVo.getPage());

        LambdaQueryWrapper<BloodWarningEntity> queryWrapper = Wrappers.lambdaQuery(BloodWarningEntity.class);
        queryWrapper.eq(Strings.isNotBlank(bloodWarningQueryVo.getBloodType()), BloodWarningEntity::getBloodType, bloodWarningQueryVo.getBloodType());
        IPage<BloodWarningEntity> page = this.page(
                new Query<BloodWarningEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public int saveBloodWarning(BloodWarningEntity bloodWarning) {
        LambdaQueryWrapper<BloodWarningEntity> queryWrapper = Wrappers.lambdaQuery(BloodWarningEntity.class);
        queryWrapper.eq(Strings.isNotBlank(bloodWarning.getBloodType()), BloodWarningEntity::getBloodType, bloodWarning.getBloodType());

        // 查询数据库中是否存在该 bloodType 的记录
        int count = this.count(queryWrapper);
        if (count > 0) {
            // 如果已存在，抛出业务异常
            throw new MyException(BloodWarningEnum.ALREADY);
        }

        // 不存在，执行插入操作
        return this.baseMapper.insert(bloodWarning);
    }

    @Override
    public List<BloodTypeWarningVo> getStockWarningList() {
        // 1. 查询所有在库血袋
        List<BloodInformationEntity> inStockList = bloodInformationService.list(
                new LambdaQueryWrapper<BloodInformationEntity>()
                        .eq(BloodInformationEntity::getBloodState, BloodInformationEnum.BLOOD_IN_STOCK.code())
        );

        // 2. 按血液类型+abo血型分组统计实际库存
        Map<String, Map<String, List<BloodInformationEntity>>> grouped =
                inStockList.stream().collect(
                        Collectors.groupingBy(
                                BloodInformationEntity::getBloodType,
                                Collectors.groupingBy(BloodInformationEntity::getAboBloodType)
                        )
                );

        List<BloodTypeWarningVo> result = new ArrayList<>();

        // 3. 查询所有血液类型+abo血型的安全库存
        List<BloodWarningEntity> warningList = this.list();
        for (BloodWarningEntity warning : warningList) {
            String bloodType = warning.getBloodType();
            String aboBloodType = warning.getAboBloodType();
            Integer safeStock = warning.getSafeStock() == null ? 0 : warning.getSafeStock();

            // 4. 获取实际库存
            int actualStock = 0;
            if (grouped.containsKey(bloodType) && grouped.get(bloodType).containsKey(aboBloodType)) {
                actualStock = grouped.get(bloodType).get(aboBloodType).size();
            }

            // 5. 如果实际库存小于安全库存，加入结果
            if (actualStock < safeStock) {
                BloodTypeWarningVo vo = new BloodTypeWarningVo();
                vo.setBloodType(bloodType);
                vo.setComponentCategory(warning.getComponentCategory());
                vo.setSafeStock(safeStock);
                vo.setActualStock(actualStock);
                vo.setAboBloodType(aboBloodType);
                result.add(vo);
            }
        }
        return result;
    }

    @Override
    public String getComponentCategory(String bloodType) {
        Map<String, String> dictCodeMap = dictBloodProductLoader.getchildToParent();
        return  dictCodeMap.get(bloodType);
    }
}